# -*- coding: utf-8 -*-
"""
本脚本用于通过接口获取设备流量报表数据，并支持将返回的table body部分处理为时间戳格式及自定义列名。
用法示例：
    python get_flow_report.py 1 "2025-06-09 00:00:00" "2025-06-13 00:00:00"
"""
import sys
import traceback

import requests
from .authentication import get_request_head_token
import time
import datetime
from loguru import logger
import pandas as pd
import aiohttp
import asyncio
import hashlib
import re

#URL = "http://192.168.1.102:8200/yunqi/e-server-device-service/flowReport"
#URL_CONTROL = "http://192.168.1.102:8200/yunqi/e-server-logtask-service/wulian/command/BDNv3mmWDaDniBMzof8M4Q=="
#URL = "http://10.47.40.243:8200/yunqi/e-server-device-service/flowReport"
#URL_CONTROL = "http://10.47.40.243:8200/yunqi/e-server-logtask-service/wulian/command/BDNv3mmWDaDniBMzof8M4Q=="
URL = "http://server.yunhanenergy.com:8200/yunqi/e-server-device-service/flowReport"  # 轻纺城正式服请求链接
# URL = "http://192.168.1.125:8200/yunqi/e-server-device-service/flowReport"  # 轻纺城测试服请求链接
URL_CONTROL = "http://10.47.40.243:8200/yunqi/e-server-logtask-service/wulian/command/BDNv3mmWDaDniBMzof8M4Q=="
#URL = "http://manage.yunhanenergy.com:8200/yunqi/e-server-device-service/flowReport"

def get_flow_report_history(id, start_time, end_time, rename_map=None):
    """
    根据输入的id、开始时间、结束时间，请求接口获取报表数据，并处理table body部分。
    Args:
        id: 设备id
        start_time: 查询开始时间，格式如'2025-06-09 00:00:00'
        end_time: 查询结束时间，格式如'2025-06-13 00:00:00'
        rename_map: 可选，dict，key为原key，value为新列名
    Returns:
        list[dict]，每行为一条数据，ts为时间戳
    """
    url = URL +"/view/"+ str(id)
    querystring = {
        "startTime": start_time,
        "endTime": end_time
    }
    # 获取token
    token = get_request_head_token()
    logger.info(f"token: {token}")
    #token = "eyJhbGciOiJSUzI1NiJ9.eyJzY29wZSI6InBsYXRGb3JtIiwiZS1zZXJ2ZXItdXNlciI6IntcImdyb3VwSWRcIjoxLFwiZ3JvdXBOYW1lXCI6XCLotoXnuqfnrqHnkIblkZhcIixcImhlYWRQaWNcIjpcImh0dHA6Ly9iZ3MueXVuaGFuZW5lcmd5LmNvbToxODI1My91cGxvYWQvaGVhZHMvODRkZmM4YzgtYWJhNS00NDM0LWI1ZTktODM3NjQ0YmRjNGM2LnBuZ1wiLFwiaWRcIjoxLFwiaXBcIjpcIjEyNy4wLjAuMVwiLFwiaXNBZG1pblwiOjEsXCJ0cnVlbmFtZVwiOlwi6LaF57qn566h55CG5ZGYXCJ9IiwianRpIjoiNTZkNjJiYzItYmI3OS00Y2E5LTg1NTktMTFkM2Q1MGZjMjM0IiwiZXhwIjoxNzUxNTU4NDAwfQ.mQVD0Xs7UyRnKnzTpfiFMa31Ju8QTD_3zVR-mR92V0kuQKuILYerbf9BDTUvtkf2VBsXN7Ox8X1yqic-UK7vRHkk6YfSzkLf3q-ZQaqtuSeT1TBvt-lKFW0N4w8PhyspFnKpjmijN0v1U7njLbgquI04xGIlcfp2nI9y4OLnRTtlU89hltlgjv3ecWQx7zAza4LMu8MiCxgs-oipDi3scf-JULOTtyu91LUlEjLDCAYmvRyMPEOK1wMbMAixhHS7Ocmt0XBPA2ldDZOxVbwPdAwp82g9CJUjC_LojnPc9ZiCRmhciMTVIp9vGjG2ARCZcR2lkZw6FM3l0DstlWT9uw"
    headers = {
        "e-server-user": token,
        "token": "yunqi",
        "hypToken": "FRH+G4Pv/BmVeniiNwCdoJ3ISopvSvX8jhzD/YFBoIxY9KWQdKyI9ztZOX5ouNohKj8XiO4jowgZmIcgkclWgLJFHk8HvJ3zl3BcpZyozq9pXaL+OtAZHZQnF0n1/5xIuXzsTF/kqYkMct3RBeBy213jqtnFBLeL/WhOEFzT4rJ1LsbuoztRXOzNhsBiB44RFBuoc/ppfpBNIRWGzcEE4XWUaWEyWj0qmXEHKueuiLF8LJ4KQd0ZwD3y0zG53agcOCe65V5JFQTcafGe30VcNQgQJ2yUaf22MfAUoBdX5Io=",
        "Content-Type": "application/json",
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate, br",
        "User-Agent": "PostmanRuntime-ApipostRuntime/1.1.0",
        "Connection": "keep-alive"
    }
    max_retries = 1
    for attempt in range(max_retries):
        try:
            response = requests.get(url, headers=headers, params=querystring)
            logger.info(f"response: {response}")
            resp_json = response.json()

            logger.info(f'看看调用接口的参数时间：\n{start_time} - {end_time}')

            table_result = extract_table_body_from_response(resp_json, rename_map=rename_map)
            logger.info(f'看看返回的数据\n{table_result}')

            # table_result['real_load'] = table_result['real_load'].shift(1)
            # table_result['real_load'] = table_result['real_load'].fillna(0)

            return table_result
        except Exception as e:
            if attempt < max_retries - 1:
                time.sleep(1)  # 等待1秒后重试
            else:
                logger.error(f"多次请求api或解析数据失败：{traceback.format_exc()}")
                raise Exception("多次请求api或解析数据失败：", e)


def extract_table_body_from_response(resp_json, rename_map=None):
    """
    先用header的title替换body的key，再根据rename_map进一步重命名。
    Args:
        resp_json: 接口返回的json对象
        rename_map: 可选，dict，key为原key，value为新列名
    Returns:
        list[dict]，每行为一条数据，列名为header的title，且可进一步重命名
    """
    table = resp_json.get('data', {}).get('table', {})
    header = table.get('header', [])
    body = table.get('body', [])

    # 构建dataIndex到title的映射
    key2title = {col['dataIndex']: col['title'] for col in header}

    result = []
    for row in body:
        new_row = {}
        for k, v in row.items():
            col_name = key2title.get(k, k)  # 先用title，没有就用原key
            # 再根据rename_map重命名
            if rename_map and col_name in rename_map:
                col_name = rename_map[col_name]
            new_row[col_name] = v
        result.append(new_row)
    return pd.DataFrame(result)


def get_last_data(device_fields):
    """
    获取指定设备和字段的最新数据
    Args:
        device_fields: list，每个元素为dict，包含deviceId和field两个字段
                       例如：[{"deviceId": 7, "field": "dd"}, {"deviceId": 20, "field": "gpzt"}]
    Returns:
        返回接口响应的数据部分
    """
    # url = "http://192.168.1.102:8200/yunqi/e-server-device-service/flowReport/queryLastData"
    url = URL + "/queryLastData"
    # 获取token
    token = get_request_head_token()
    
    headers = {
        "e-server-user": token,
        "token": "yunqi",
        "hypToken": "FRH+G4Pv/BmVeniiNwCdoJ3ISopvSvX8jhzD/YFBoIxY9KWQdKyI9ztZOX5ouNohKj8XiO4jowgZmIcgkclWgLJFHk8HvJ3zl3BcpZyozq9pXaL+OtAZHZQnF0n1/5xIuXzsTF/kqYkMct3RBeBy213jqtnFBLeL/WhOEFzT4rJ1LsbuoztRXOzNhsBiB44RFBuoc/ppfpBNIRWGzcEE4XWUaWEyWj0qmXEHKueuiLF8LJ4KQd0ZwD3y0zG53agcOCe65V5JFQTcafGe30VcNQgQJ2yUaf22MfAUoBdX5Io=",
        "Content-Type": "application/json",
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate, br",
        "User-Agent": "PostmanRuntime-ApipostRuntime/1.1.0",
        "Connection": "keep-alive"
    }
    
    max_retries = 3
    for attempt in range(max_retries):
        try:
            response = requests.post(url, json=device_fields, headers=headers)
            resp_json = response.json()
            return resp_json.get('data', [])
        except Exception as e:
            if attempt < max_retries - 1:
                time.sleep(1)  # 等待1秒后重试
            else:
                logger.warning(f"device_fields:{device_fields} 多次请求api或解析数据失败：{e}")
                return None

# 对设备进行控制
# 参考用户提供的POST请求方式，完善函数

def control_device(device_fields):
    """
    对设备进行控制
    Args:
        device_fields: list，每个元素为dict，包含deviceId,field,value三个字段
                       例如：[{"deviceId": 7, "field": "dd", "value": 100}, {"deviceId": 20, "field": "gpzt", "value": 1}]
    Returns:
        成功返回True，失败返回False和错误信息
    """
    url = URL_CONTROL

    # 获取token
    token = get_request_head_token()
    headers = {
        "e-server-user": token,
        "token": "yunqi",
        "hypToken": "FRH+G4Pv/BmVeniiNwCdoJ3ISopvSvX8jhzD/YFBoIxY9KWQdKyI9ztZOX5ouNohKj8XiO4jowgZmIcgkclWgLJFHk8HvJ3zl3BcpZyozq9pXaL+OtAZHZQnF0n1/5xIuXzsTF/kqYkMct3RBeBy213jqtnFBLeL/WhOEFzT4rJ1LsbuoztRXOzNhsBiB44RFBuoc/ppfpBNIRWGzcEE4XWUaWEyWj0qmXEHKueuiLF8LJ4KQd0ZwD3y0zG53agc74uBjPfy20y1uYndLat3UT8RAaCqkp7ExYLIdNdGUrY=",
        "Content-Type": "application/json",
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate, br",
        "User-Agent": "PostmanRuntime-ApipostRuntime/1.1.0",
        "Connection": "keep-alive"
    }
    try:
        response = requests.post(url, json=device_fields, headers=headers)
        resp_json = response.json()
        if resp_json.get("code") == 0:
            return True
        else:
            logger.error(f"控制设备失败，返回内容: {resp_json}")
            return False, resp_json
    except Exception as e:
        logger.error(f"控制设备异常: {e}")
        return False, str(e)


async def control_device_async(device_fields):
    """
    对设备进行异步控制
    Args:
        device_fields: list，每个元素为dict，包含deviceId,field,value三个字段
                       例如：[{"deviceId": 7, "field": "dd", "value": 100}, {"deviceId": 20, "field": "gpzt", "value": 1}]
    Returns:
        成功返回True，失败返回(False, error_message)
    """

    
    url = URL_CONTROL

    # 获取token
    token = get_request_head_token()
    headers = {
        "e-server-user": token,
        "token": "yunqi",
        "hypToken": "FRH+G4Pv/BmVeniiNwCdoJ3ISopvSvX8jhzD/YFBoIxY9KWQdKyI9ztZOX5ouNohKj8XiO4jowgZmIcgkclWgLJFHk8HvJ3zl3BcpZyozq9pXaL+OtAZHZQnF0n1/5xIuXzsTF/kqYkMct3RBeBy213jqtnFBLeL/WhOEFzT4rJ1LsbuoztRXOzNhsBiB44RFBuoc/ppfpBNIRWGzcEE4XWUaWEyWj0qmXEHKueuiLF8LJ4KQd0ZwD3y0zG53agc74uBjPfy20y1uYndLat3UT8RAaCqkp7ExYLIdNdGUrY=",
        "Content-Type": "application/json",
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate, br",
        "User-Agent": "PostmanRuntime-ApipostRuntime/1.1.0",
        "Connection": "keep-alive"
    }
    
    try:
        async with aiohttp.ClientSession() as session:
            async with session.post(url, json=device_fields, headers=headers) as response:
                resp_json = await response.json()
                if resp_json.get("code") == 0:
                    return True
                else:
                    logger.error(f"异步控制设备失败，返回内容: {resp_json}")
                    return False, resp_json
    except Exception as e:
        logger.error(f"异步控制设备异常: {e}")
        return False, str(e)

async def get_last_data_async(device_fields):
    """
    异步获取指定设备和字段的最新数据
    Args:
        device_fields: list，每个元素为dict，包含deviceId和field两个字段
    Returns:
        返回接口响应的数据部分，或None
    """
    url = URL + "/queryLastData"
    token = get_request_head_token()  # 假设这个是同步的，如果需要，可异步化
    
    headers = {
        "e-server-user": token,
        "token": "yunqi",
        "hypToken": "FRH+G4Pv/BmVeniiNwCdoJ3ISopvSvX8jhzD/YFBoIxY9KWQdKyI9ztZOX5ouNohKj8XiO4jowgZmIcgkclWgLJFHk8HvJ3zl3BcpZyozq9pXaL+OtAZHZQnF0n1/5xIuXzsTF/kqYkMct3RBeBy213jqtnFBLeL/WhOEFzT4rJ1LsbuoztRXOzNhsBiB44RFBuoc/ppfpBNIRWGzcEE4XWUaWEyWj0qmXEHKueuiLF8LJ4KQd0ZwD3y0zG53agcOCe65V5JFQTcafGe30VcNQgQJ2yUaf22MfAUoBdX5Io=",
        "Content-Type": "application/json",
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate, br",
        "User-Agent": "PostmanRuntime-ApipostRuntime/1.1.0",
        "Connection": "keep-alive"
    }
    
    max_retries = 3
    for attempt in range(max_retries):
        try:
            async with aiohttp.ClientSession() as session:
                async with session.post(url, json=device_fields, headers=headers) as response:
                    resp_json = await response.json()
                    return resp_json.get('data', {})
        except Exception as e:
            if attempt < max_retries - 1:
                await asyncio.sleep(1)  # 异步等待1秒后重试
            else:
                logger.warning(f"device_fields:{device_fields} 多次异步请求api或解析数据失败：{e}")
                return None

def create_fuzzy_rename_map(available_columns, pattern_map):
    """
    创建模糊搜索的重命名映射
    
    该函数根据模式匹配规则，从可用列名中找到匹配的列名，并创建重命名映射。
    支持正则表达式模式匹配，提高函数的通用性。
    
    Args:
        available_columns (list): 可用的列名列表
        pattern_map (dict): 模式映射字典，key为正则表达式模式，value为目标列名
                          例如: {
                              r'冷冻机热量表\d+-回水温度': 't_LD_in',
                              r'冷冻机\d+-蒸发器出水温度.*': 't_LD_out'
                          }
    
    Returns:
        dict: 精确的重命名映射字典，key为实际列名，value为目标列名
    
    Raises:
        ValueError: 当模式匹配失败时
    
    Author: zq
    Date: 27.12.2024 15:30:00
    Version: 1.0
    """
    rename_map = {}
    
    for pattern, target_name in pattern_map.items():
        matched = False
        for col in available_columns:
            if re.search(pattern, col):
                rename_map[col] = target_name
                matched = True
                logger.info(f"模糊匹配成功: '{col}' -> '{target_name}'")
                break  # 找到第一个匹配的就停止
        
        if not matched:
            logger.warning(f"模式 '{pattern}' 未找到匹配的列名")
    
    return rename_map


def get_flow_report_with_fuzzy_rename(id, start_time, end_time, pattern_map=None, exact_rename_map=None):
    """
    获取流量报表数据并支持模糊重命名
    
    该函数首先获取数据的列名，然后根据模式映射创建精确的重命名映射，
    最后调用原始的get_flow_report函数进行数据获取和重命名。
    
    Args:
        id (int): 设备ID
        start_time (str): 开始时间
        end_time (str): 结束时间
        pattern_map (dict, optional): 模糊匹配模式映射
        exact_rename_map (dict, optional): 精确匹配重命名映射
    
    Returns:
        pd.DataFrame: 重命名后的数据框
    """
    # 首先获取一小段数据来获取列名
    # 将start_time转换为datetime并加上1小时
    start_time_1 = (datetime.datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S") + datetime.timedelta(hours=1)).strftime("%Y-%m-%d %H:%M:%S")
    temp_data = get_flow_report_history(id=id, start_time=start_time, end_time=start_time_1, rename_map={})
    available_columns = temp_data.columns.tolist()
    
    # 创建最终的重命名映射
    final_rename_map = {}
    
    # 添加模糊匹配的映射
    if pattern_map:
        fuzzy_map = create_fuzzy_rename_map(available_columns, pattern_map)
        final_rename_map.update(fuzzy_map)
    
    # 添加精确匹配的映射
    if exact_rename_map:
        final_rename_map.update(exact_rename_map)
    
    # 获取完整数据
    return get_flow_report_history(id=id, start_time=start_time, end_time=end_time, rename_map=final_rename_map)


if __name__ == "__main__":
    # 测试获取流量报表
    id = 37
    start_time = "2025-06-09 00:00:00"
    end_time = "2025-06-20 00:00:00"
    table_result = get_flow_report_history(id, start_time, end_time) 
    print(table_result)
    
    # 测试获取最新数据
    device_fields = [
        {"deviceId": 53, "field": "sd"},
        {"deviceId": 20, "field": "gpzt"},
        {"deviceId": 12, "field": "dd"}
    ]
    last_data = get_last_data(device_fields)
    print("最新数据结果：")
    print(last_data)
    data = get_last_data([
    {"deviceId": 107, "field": "wdreal"},   # 环境温度
    {"deviceId": 107, "field": "sd"},       # 环境湿度
    {"deviceId": 105, "field": "wdreal"},  # 回风温度
    {"deviceId": 105, "field": "sd"},      # 回风湿度
    {"deviceId": 17, "field": "kqzt"},     # 阀门1
    {"deviceId": 39, "field": "kqzt"},     # 阀门2
    {"deviceId": 37, "field": "kqzt"},     # 阀门3
    {"deviceId": 180, "field": "dsll"},    # 系统流量
    {"deviceId": 157, "field": "ldpl1"},   # 水泵频率
    ])
    # 环境温度和湿度
    env_temp = env_hum = None
    for item in data:
        if item.get("deviceId") == 107 and item.get("field") == "wdreal":
            env_temp = float(item.get("value"))
        if item.get("deviceId") == 107 and item.get("field") == "sd":
            env_hum = float(item.get("value"))

    # 回风温度和湿度
    rf_temp = rf_hum = None
    for item in data:
        if item.get("deviceId") == 105 and item.get("field") == "wdreal":
            rf_temp = float(item.get("value"))
        if item.get("deviceId") == 105 and item.get("field") == "sd":
            rf_hum = float(item.get("value"))